#pragma once

#include <iostream>
#include <sys/epoll.h>
#include "./module/log.hpp"
#include "./module/comm.hpp"
using namespace MyLog;

class Epoller
{
public:
    Epoller():_epfd(-1)
    {
        _epfd = epoll_create(128);
        if(_epfd < 0) {
            LOG(loglevel::FATAL) << "create epoll error";
            exit(CREATE_EPOLL_ERR);
        }
        LOG(loglevel::DEBUG) << "create epoll success: " << _epfd;
    }

    ~Epoller()
    {
        if(_epfd > 0) { close(_epfd); }
    }


    void addEvent(int fd, uint32_t event) { eventOper(fd, event, EPOLL_CTL_ADD); }
    void delEvent(int fd) { eventOper(fd, 0, EPOLL_CTL_DEL); }
    void modEvent(int fd, uint32_t event) { eventOper(fd, event, EPOLL_CTL_MOD); }

    int waitEvent(struct epoll_event rev[], int maxsize, int timeout) 
    {
        int n = epoll_wait(_epfd, rev, maxsize, timeout);
        if(n < 0) {
            LOG(loglevel::ERROR) << "epoll_wait error";
        }
        else if(n == 0) {
            LOG(loglevel::INFO) << "epoll_wait timeout...";
        }
        return n;
    }
private:
    void eventOper(int fd, uint32_t event, int oper) 
    {
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = fd;
        int n = epoll_ctl(_epfd, oper, fd, &ev);
        if(oper == EPOLL_CTL_ADD) {
            if(n < 0) {
                LOG(loglevel::ERROR) << "epoll_ctl add event error";
                return;
            }
            LOG(loglevel::INFO) << "epoll_ctl add event success: " << fd;
        }
        else if(oper == EPOLL_CTL_DEL) {
            if(n < 0) {
                LOG(loglevel::ERROR) << "epoll_ctl del event error";
                return;
            }
            LOG(loglevel::INFO) << "epoll_ctl del event success: " << fd;
        }
        else {
            if(n < 0) {
                LOG(loglevel::ERROR) << "epoll_ctl mod event error";
                return;
            }
            LOG(loglevel::INFO) << "epoll_ctl mod event success: " << fd;
        }
    }
private:
    int _epfd;
};